package com.aitao.util.cmd;


import com.aitao.exception.CmdRunException;
import com.aitao.util.Assert;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;


/**
 * 命令行实体类
 *
 * @Company QAX
 * @Author : admin
 * @Create : 2022/1/10 17:40
 */
public class Cmd {
    private final String message = "Cmd#%s  Execution error";
    private final Process process;
    private final InputStream input;
    private final InputStream error;
    private BufferedReader reader;

    public Cmd(Process process) {
        this.process = process;
        this.input = process.getInputStream();
        this.error = process.getErrorStream();
    }

    /**
     * 获取输出信息
     *
     * @return 输出信息
     */
    public String result() {
        try {
            if (process != null) {
                return getResult(input, false);
            }
            return "";
        } catch (Exception e) {
            throw new CmdRunException(Assert.mark(String.format(message, "result()"), new Throwable()), e);
        }
    }

    /**
     * 获取输出信息
     *
     * @param charset 编码格式
     * @return 输出信息
     */
    public String result(String charset) {
        try {
            if (process != null) {
                return getResult(input, charset, false);
            }
            return "";
        } catch (Exception e) {
            throw new CmdRunException(Assert.mark(String.format(message, "result(String charset)"), new Throwable()), e);
        }
    }

    /**
     * 控制台输出
     */
    public void console() {
        try {
            getResult(input, true);
            getResult(error, true);
        } catch (IOException | InterruptedException e) {
            throw new CmdRunException(Assert.mark(String.format(message, "console()"), new Throwable()), e);
        }
    }

    /**
     * 控制台输出
     *
     * @param charset 编码格式
     */
    public void console(String charset) {
        try {
            getResult(input, charset, true);
            getResult(error, charset, true);
        } catch (IOException | InterruptedException e) {
            throw new CmdRunException(Assert.mark(String.format(message, "console(String charset)"), new Throwable()), e);
        }
    }

    /**
     * 获取错误信息
     *
     * @return 错误信息
     */
    public String error() {
        try {
            if (process != null) {
                return getResult(error, false);
            }
        } catch (Exception e) {
            throw new CmdRunException(Assert.mark(String.format(message, "error()"), new Throwable()), e);
        }
        return null;
    }

    /**
     * 获取错误信息
     *
     * @param charset 编码格式
     */
    public String error(String charset) {
        try {
            if (process != null) {
                return getResult(error, charset, false);
            }
        } catch (Exception e) {
            throw new CmdRunException(Assert.mark(String.format(message, "error(String charset)"), new Throwable()), e);
        }
        return null;
    }

    /**
     * 关闭流
     */
    public void close() {
        try {
            if (reader != null) {
                reader.close();
            }
        } catch (IOException e) {
            throw new CmdRunException(Assert.mark(String.format(message, "close()"), new Throwable()), e);
        }
    }

    /**
     * 终止进程
     */
    public void destroy() {
        if (process != null) {
            process.destroyForcibly();
        }
    }

    /**
     * 获取结果
     *
     * @param is 进程中的输出信息或错误信息
     * @param charset 编码格式
     * @param isRealtime 是否实时输出
     * @return 结果
     * @throws IOException 处理流时可能会异常
     */
    private String getResult(InputStream is, String charset, boolean isRealtime)
        throws IOException, InterruptedException {
        reader = new BufferedReader(new InputStreamReader(is, charset));
        StringBuffer buff = new StringBuffer("");
        String temp;
        while ((temp = reader.readLine()) != null) {
            if (isRealtime && !temp.isEmpty()) {
                System.out.println("[INFO] " + temp);
            } else {
                buff.append(temp).append("\r\n");
            }
        }
        if (process.waitFor() == 0) {
            destroy();
            close();
        }
        return buff.toString().trim();
    }

    /**
     * 获取结果
     *
     * @param is 进程中的输出信息或错误信息
     * @param isRealtime 是否实时输出
     * @return 结果
     * @throws IOException 处理流时可能会异常
     */
    private String getResult(InputStream is, boolean isRealtime) throws IOException, InterruptedException {
        return getResult(is, "GBK", isRealtime);
    }
}